﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace LastoRevival.Website.Engine
{
	public class OverridableViewEngine : RazorViewEngine
	{
		public const string LayoutCookieName = "__UseMobileLayout";
		
		private enum Layout
		{
			Standard,
			Mobile,
		}

		public static bool IsMobile(HttpContextBase context)
		{
			var cookie = context.Request.Cookies[LayoutCookieName];

			if (cookie == null)
				return false;

			var isMobile = false;
			bool.TryParse(cookie.Value, out isMobile);

			return isMobile;
		}

		public static void SetLayout(HttpContextBase context, bool isMobile, bool always)
		{
			var cookie = new HttpCookie(LayoutCookieName, isMobile.ToString());

			if (always)
			{
				cookie.Expires = DateTime.MaxValue;
			}

			context.Response.Cookies.Add(cookie);
		}


		private static string GetLayout(HttpContextBase context)
		{
			return IsMobile(context) ? Layout.Mobile.ToString() : Layout.Standard.ToString();
		}

		public OverridableViewEngine()
		{

			// paths to view pages
			ViewLocationFormats = new[]
                {
					//"~/Views/{2}/{1}/{0}.cshtml",
					//"~/Views/{2}/{1}/{0}.vbhtml",
					//"~/Views/{2}/Shared/{0}.cshtml",
					//"~/Views/{2}/Shared/{0}.vbhtml",
					//"~/Views/Shared/{0}.cshtml",
					//"~/Views/Shared/{0}.vbhtml",
					//"~/Views/" + Layout.Standard.ToString() + "/{1}/{0}.cshtml", // fall back to standard theme
					//"~/Views/" + Layout.Standard.ToString() + "/{1}/{0}.vbhtml",
										
					"~/Views/{1}/{0}.cshtml",
					"~/Views/{1}/{0}.vbhtml",
					"~/Views/Shared/{0}.cshtml",
					"~/Views/Shared/{0}.vbhtml",
                };

			// paths to partial views
			PartialViewLocationFormats = new[]
                {
					//"~/Views/{2}/{1}/{0}.cshtml",
					//"~/Views/{2}/{1}/{0}.vbhtml",
					//"~/Views/{2}/Shared/{0}.cshtml",
					//"~/Views/{2}/Shared/{0}.vbhtml",
					//"~/Views/Shared/{0}.cshtml",
					//"~/Views/Shared/{0}.vbhtml",
					//"~/Views/" + Layout.Standard.ToString() + "/{1}/{0}.cshtml", // fall back to standard theme
					//"~/Views/" + Layout.Standard.ToString() + "/{1}/{0}.vbhtml",
					
					"~/Views/{1}/{0}.cshtml",
					"~/Views/{1}/{0}.vbhtml",
					"~/Views/Shared/{0}.cshtml",
					"~/Views/Shared/{0}.vbhtml",
                };
		}

		//protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
		//{
		//    return new ThemedView(viewPath, masterPath);
		//}

		public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
		{
			if (controllerContext == null)
				throw new ArgumentNullException("controllerContext");

			if (string.IsNullOrEmpty(viewName))
				throw new ArgumentException("Value is required.", "viewName");

			var themeName = GetLayout(controllerContext.RequestContext.HttpContext);

			string[] searchedViewLocations;
			string[] searchedMasterLocations;

			string controllerName = controllerContext.RouteData.GetRequiredString("controller");

			string viewPath = this.GetPath(controllerContext, this.ViewLocationFormats, "ViewLocationFormats",
				viewName, themeName, controllerName, "View", useCache, out searchedViewLocations);


			string masterPath = this.GetPath(controllerContext, this.MasterLocationFormats, "MasterLocationFormats",
				masterName, themeName, controllerName, "Master", useCache, out searchedMasterLocations);


			if (!(string.IsNullOrEmpty(viewPath)) && (!(masterPath == string.Empty) || string.IsNullOrEmpty(masterName)))
				return new ViewEngineResult(this.CreateView(controllerContext, viewPath, masterPath), this);

			return new ViewEngineResult(searchedViewLocations.Union<string>(searchedMasterLocations));
		}

		public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
		{
			if (controllerContext == null)
				throw new ArgumentNullException("controllerContext");

			if (string.IsNullOrEmpty(partialViewName))
				throw new ArgumentException("Value is required.", partialViewName);

			string themeName = GetLayout(controllerContext.HttpContext);

			string[] searchedLocations;

			string controllerName = controllerContext.RouteData.GetRequiredString("controller");

			string partialPath = this.GetPath(controllerContext, this.PartialViewLocationFormats,
				"PartialViewLocationFormats", partialViewName, themeName, controllerName, "Partial", useCache, out searchedLocations);

			if (string.IsNullOrEmpty(partialPath))
				return new ViewEngineResult(searchedLocations);

			return new ViewEngineResult(this.CreatePartialView(controllerContext, partialPath), this);
		}



		private static readonly string[] emptyLocations = new string[] { };

		private string GetPath(ControllerContext controllerContext, string[] locations, string locationsPropertyName,
		string viewName, string themeName, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations)
		{
			//searchedLocations = new string[locations.Length*2];
			searchedLocations = emptyLocations;


			// primary code sample
			if (string.IsNullOrEmpty(viewName))
			{
				return string.Empty;
			}

			if ((locations.Length == 0))
			{
				throw new InvalidOperationException("locations must not be null or empty.");
			}

			bool flag = IsSpecificPath(viewName);
			string key = this.CreateCacheKey(cacheKeyPrefix, viewName, flag ? string.Empty : controllerName, themeName);

			if (useCache)
			{
				string viewLocation = this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key);
				if (viewLocation != null)
				{
					return viewLocation;
				}
			}

			if (!flag)
			{
				return this.GetPathFromGeneralName(controllerContext, locations, viewName, controllerName, themeName, key, ref searchedLocations);
			}

			return this.GetPathFromSpecificName(controllerContext, viewName, key, ref searchedLocations);

		}

		private static bool IsSpecificPath(string name)
		{
			char ch = name[0];
			if (ch != '~')
			{
				return (ch == '/');
			}
			return true;
		}

		private string CreateCacheKey(string prefix, string name, string controllerName, string themeName)
		{
			return string.Format(CultureInfo.InvariantCulture,
				":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}",
				new object[] { base.GetType().AssemblyQualifiedName, prefix, name, controllerName, themeName });
		}

		private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string themeName, string cacheKey, ref string[] searchedLocations)
		{
			string virtualPath = string.Empty;
			searchedLocations = new string[locations.Length];
			for (int i = 0; i < locations.Length; i++)
			{
				string str2 = string.Format(CultureInfo.InvariantCulture, locations[i], new object[] { name, controllerName, themeName });

				if (this.FileExists(controllerContext, str2))
				{
					searchedLocations = emptyLocations;
					virtualPath = str2;
					this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
					return virtualPath;
				}
				searchedLocations[i] = str2;
			}
			return virtualPath;
		}

		private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations)
		{
			string virtualPath = name;
			if (!this.FileExists(controllerContext, name))
			{
				virtualPath = string.Empty;
				searchedLocations = new string[] { name };
			}
			this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
			return virtualPath;
		}


	}
}
